/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.springblade.common.utils.CommonUtil;
import org.springblade.common.utils.PoiExcelUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;

import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.vo.brand.BrandVersionUploadResultVo;
import org.springblade.modules.admin.vo.brand.BrandVersionUploadVo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestParam;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.admin.vo.BrandVersionVO;
import org.springblade.modules.admin.wrapper.BrandVersionWrapper;
import org.springblade.core.boot.ctrl.BladeController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 控制器
 *
 * @author ysq
 * @since 2023-08-10
 */
@RestController
@AllArgsConstructor
@RequestMapping("admin/brand/version")
@Api(value = "品牌型号管理", tags = "品牌型号管理")
public class BrandVersionController extends BladeController {

	private final static String DOWN_EXCLE_ERROR_KEY = "brand_version:";
	private final IElevatorBrandService elevatorBrandService;
	private final IBrandVersionService brandVersionService;
	private final IBrandVersionSkuService brandVersionSkuService;
	private final ElevatorService elevatorService;
	private final RedisTemplate redisTemplate;

	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入brandVersion")
	public R<BrandVersionVO> detail(BrandVersion brandVersion) {
		BrandVersion detail = brandVersionService.getOne(Condition.getQueryWrapper(brandVersion));
		if (StrUtil.isNotEmpty(brandVersion.getName())) {
			if (brandVersion.getId().equals(detail.getId())) {
				return R.data(null);
			}
		}
		return R.data(BrandVersionWrapper.build().entityVO(detail));
	}

	/**
	 * 列表
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "列表", notes = "传入brandVersion")
	public R<List<BrandVersion>> list(BrandVersion brandVersion) {
		if (ObjectUtil.isNotEmpty(brandVersion) && ObjectUtil.isNotEmpty(brandVersion.getBrandId())) {
			return R.data(brandVersionService.list(Wrappers.<BrandVersion>lambdaQuery().eq(BrandVersion::getBrandId, brandVersion.getBrandId())));
		} else {
			return R.data(brandVersionService.list());
		}
	}

	/**
	 * 自定义分页
	 */
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "分页", notes = "传入brandVersion")
	public R<IPage<BrandVersionVO>> page(BrandVersionVO brandVersion, Query query) {
		IPage<BrandVersionVO> pages = brandVersionService.selectBrandVersionPage(Condition.getPage(query), brandVersion);
		return R.data(pages);
	}

	/**
	 * 新增
	 */
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "新增", notes = "传入brandVersion")
	public R save(@Valid @RequestBody BrandVersion brandVersion) {
		List<BrandVersion> versionList = brandVersionService.list(Wrappers.<BrandVersion>lambdaQuery().eq(BrandVersion::getBrandId, brandVersion.getBrandId()).eq(BrandVersion::getName, brandVersion.getName()));
		if (versionList.size() > 0) {
			throw new ServiceException("存在相同的型号");
		}
		return R.status(brandVersionService.save(brandVersion));
	}

	/**
	 * 新增
	 */
	@GetMapping("/isExist")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "校验重复", notes = "传入brandVersion")
	public R<Boolean> isExist(BrandVersion brandVersion) {
		List<BrandVersion> brandVersions = brandVersionService.list(Wrappers.<BrandVersion>lambdaQuery().eq(BrandVersion::getBrandId, brandVersion.getBrandId()).eq(BrandVersion::getName, brandVersion.getName()));
		if (brandVersions.size() > 0 && brandVersion.getId() != null) {
			if (brandVersions.get(0).getId().equals(brandVersion.getId())) {
				return R.data(false);
			}
		}
		return R.data(brandVersions.size() > 0 ? true : false);
	}


	/**
	 * 新增
	 */
	@GetMapping("/influence")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "校验影响的梯数", notes = "传入brandVersion")
	public R<Integer> influenceElevator(BrandVersion brandVersion) {
		List<Elevator> elevatorList = elevatorService.list(Wrappers.<Elevator>lambdaQuery().eq(Elevator::getBrandVId, brandVersion.getId()));
		return R.data(elevatorList.size());
	}


	/**
	 * 修改
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入brandVersion")
	public R update(@Valid @RequestBody BrandVersion brandVersion) {
		return R.status(brandVersionService.updateById(brandVersion));
	}

	/**
	 * 新增或修改
	 */
	@PostMapping("/submit")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "新增或修改", notes = "传入brandVersion")
	public R submit(@Valid @RequestBody BrandVersion brandVersion) {
		return R.status(brandVersionService.saveOrUpdate(brandVersion));
	}


	/**
	 * 删除
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(brandVersionService.deleteLogic(Func.toLongList(ids)));
	}


	@ApiOperation("excel下载错误信息")
	@PostMapping("down/error/excel")
	public void downExcel(HttpServletResponse response, @RequestBody BrandVersionUploadResultVo brandVersionUploadResultVo) throws IOException {
		final String toStr = Convert.toStr(redisTemplate.opsForValue().get(brandVersionUploadResultVo.getDownExcelKey()));
		List<BrandVersionUploadVo> brandVersionUploadVos = JSON.parseArray(toStr, BrandVersionUploadVo.class);
		if (brandVersionUploadVos == null) {
			return;
		}
		XSSFWorkbook workbook = this.initExcelTemplate();
		XSSFSheet sheet = workbook.getSheetAt(0);
		for (int i = 0; i < brandVersionUploadVos.size(); i++) {
			BrandVersionUploadVo brandVersionUploadVo = brandVersionUploadVos.get(i);
			XSSFRow row = sheet.createRow(i + 3);
			row.setHeightInPoints(20);
			XSSFCell cell1 = row.createCell(0);
			cell1.setCellValue(Convert.toStr(brandVersionUploadVo.getBrandName()));
			XSSFCell cell2 = row.createCell(1);
			cell2.setCellValue(Convert.toStr(brandVersionUploadVo.getBrandVersionName()));
			XSSFCell cell3 = row.createCell(2);
			cell3.setCellValue(Convert.toStr(brandVersionUploadVo.getBrandSkuName()));
		}
		String fileName = "error-" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
		ServletOutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
			CommonUtil.setResponseHeader(response, fileName);
			workbook.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (workbook != null) {
					workbook.close();
				}
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@ApiOperation("excel上传")
	@PostMapping("upload/excel")
	public R<BrandVersionUploadResultVo> uploadExcel(@RequestParam("file") MultipartFile file) throws IOException {
		if (file.isEmpty()) {
			return R.fail("上传文件不能为空");
		}
		BrandVersionUploadResultVo brandVersionUploadResultVo = new BrandVersionUploadResultVo();
		Workbook wb = null;
		try {
			wb = WorkbookFactory.create(file.getInputStream());
		} catch (InvalidFormatException e) {
			return R.fail("请使用正确的品牌模板导入品牌");
		}
		List<Map<String, Object>> readAll = PoiExcelUtil.readExcel(wb, 0, 1, 2, 0);
		String brandNameHead = Convert.toStr(readAll.get(0).get("品牌"));
		String brandVersionNameHead = Convert.toStr(readAll.get(0).get("型号"));
		String brandSkuHead = Convert.toStr(readAll.get(0).get("型号系列"));

		if (brandNameHead == null || brandVersionNameHead == null || brandSkuHead == null) {
			brandVersionUploadResultVo.setIsTemplate(false);
			return R.data(brandVersionUploadResultVo);
		}
		if (!(brandNameHead.equals("品牌") && brandVersionNameHead.equals("型号") && brandSkuHead.equals("型号系列"))) {
			brandVersionUploadResultVo.setIsTemplate(false);
			return R.data(brandVersionUploadResultVo);
		}
		readAll.remove(0);
		if (readAll.size() == 0) {
			return R.fail("导入文件数据不能为空");
		}
		brandVersionUploadResultVo.setAllCounts(readAll.size());
		List<BrandVersionUploadVo> errorList = new ArrayList<>(16);
		for (int i = 0; i < readAll.size(); i++) {
			BrandVersionUploadVo brandVersionUploadVo = new BrandVersionUploadVo();
			Map<String, Object> map = readAll.get(i);
			String brandName = Convert.toStr(map.get("品牌"));
			String brandVersionName = Convert.toStr(map.get("型号"));
			String brandSku = Convert.toStr(map.get("型号系列"));
			brandVersionUploadVo.setNum("第" + (i + 1) + "条数据出错");
			brandVersionUploadVo.setBrandName(brandName);
			brandVersionUploadVo.setBrandVersionName(brandVersionName);
			brandVersionUploadVo.setBrandSkuName(brandSku);
			//校验是否为空
			if (StrUtil.isEmpty(brandName)) {
				brandVersionUploadVo.setErrorBody("品牌名称不能为空");
				errorList.add(brandVersionUploadVo);
				continue;
			}
			if (StrUtil.isEmpty(brandVersionName)) {
				brandVersionUploadVo.setErrorBody("型号不能为空");
				errorList.add(brandVersionUploadVo);
				continue;
			}
			//校验是否重复
			ElevatorBrand elevatorBrand = elevatorBrandService.getOne(Wrappers.<ElevatorBrand>lambdaQuery().eq(ElevatorBrand::getBrandName, brandName));
			if (elevatorBrand == null) {
				ElevatorBrand elevatorBrand1 = new ElevatorBrand();
				elevatorBrand1.setBrandName(brandName);
				elevatorBrand1.setCompanyName(brandName);
				elevatorBrand1.setStatus(3);
				elevatorBrandService.save(elevatorBrand1);
				elevatorBrand = elevatorBrand1;
			}

			BrandVersion brandVersion = brandVersionService.getOne(Wrappers.<BrandVersion>lambdaQuery().eq(BrandVersion::getName, brandVersionName).eq(BrandVersion::getBrandId, elevatorBrand.getId()));
			if (brandVersion == null) {
				BrandVersion brandVersion1 = new BrandVersion();
				brandVersion1.setName(brandVersionName);
				brandVersion1.setBrandId(elevatorBrand.getId());
				brandVersionService.save(brandVersion1);
				brandVersion = brandVersion1;
			} else if (brandVersion != null && StrUtil.isEmpty(brandSku)) {
				brandVersionUploadVo.setErrorBody("型号重复");
				errorList.add(brandVersionUploadVo);
				continue;
			}
			if (StrUtil.isNotEmpty(brandSku)) {
				BrandVersionSku brandVersionSku = brandVersionSkuService.getOne(Wrappers.<BrandVersionSku>lambdaQuery().eq(BrandVersionSku::getName, brandSku).eq(BrandVersionSku::getVersionId, brandVersion.getId()).eq(BrandVersionSku::getBrandId, elevatorBrand.getId()));
				if (brandVersionSku != null) {
					brandVersionUploadVo.setErrorBody("同品牌型号下，该型号系列已存在;");
					errorList.add(brandVersionUploadVo);
					continue;
				} else {
					BrandVersionSku brandVersionSku1 = new BrandVersionSku();
					brandVersionSku1.setBrandId(elevatorBrand.getId());
					brandVersionSku1.setVersionId(brandVersion.getId());
					brandVersionSku1.setName(brandSku);
					brandVersionSkuService.save(brandVersionSku1);
				}
			}
		}

		brandVersionUploadResultVo.setSucceedCounts(readAll.size() - errorList.size());
		brandVersionUploadResultVo.setFailCounts(errorList.size());
		brandVersionUploadResultVo.setFailList(errorList);
		brandVersionUploadResultVo.setFileName(file.getOriginalFilename());
		String key = DOWN_EXCLE_ERROR_KEY + System.currentTimeMillis();
		brandVersionUploadResultVo.setDownExcelKey(key);
		if (errorList.size() > 0) {
			redisTemplate.opsForValue().set(key, JSON.toJSON(errorList), 30, TimeUnit.MINUTES);
		}
		if (errorList.size() > 0) {
			brandVersionUploadResultVo.setResultDesc("共导入 " + readAll.size() + " 条数据，通过 " + (readAll.size() - errorList.size()) + " 条，失败 " + errorList.size() + " 条。失败原因如下:");
		} else {
			brandVersionUploadResultVo.setResultDesc("共成功导入" + readAll.size() + "条数据");
		}

		return R.data(brandVersionUploadResultVo);
	}

	/**
	 * 功能描述: 发送响应流方法
	 */
	private void setResponseHeader(HttpServletResponse response, String fileName) {
		try {
			try {
				fileName = new String(fileName.getBytes(), "ISO8859-1");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			response.setContentType("application/octet-stream;charset=ISO8859-1");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.addHeader("Pargam", "no-cache");
			response.addHeader("Cache-Control", "no-cache");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}


	/**
	 * 初始化excel模板
	 *
	 * @return
	 */
	private XSSFWorkbook initExcelTemplate() {
		XSSFWorkbook workbook = null;
		try {
			//读取源文件
			ClassPathResource resource = new ClassPathResource("templates/brand_version.xlsx");
			workbook = new XSSFWorkbook(resource.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
			throw new ServiceException("电梯模板文件异常！");
		}

		//进行模板的克隆（接下来的操作都是针对克隆后的sheet）
		XSSFSheet sheet = workbook.cloneSheet(0);
		// 行数
		final int maxRow = 1000;
		// 清空内容
		this.removeRow(sheet, 2, maxRow);

		// 自定义样式
		XSSFCellStyle style = workbook.createCellStyle();
		//自定义颜色对象
		XSSFColor color = new XSSFColor();
		int rgb = CommonUtil.getIntFromColor(217, 217, 217);
		color.setRGB(CommonUtil.intToByteArray(rgb));
		style.setFillForegroundColor(color);
		//前景填充模式
		style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		// 创建一个居中格式
		style.setAlignment(HorizontalAlignment.CENTER);
		// 垂直居中
		style.setVerticalAlignment(VerticalAlignment.CENTER);
		// 新建一个字体
		XSSFFont whiteFont = workbook.createFont();
		whiteFont.setColor(IndexedColors.BLACK.getIndex());
		whiteFont.setFontHeightInPoints((short) 12);
		style.setFont(whiteFont);
		return workbook;
	}

	/**
	 * 从某行开始，清除固定行（清除样式）
	 *
	 * @param sheet
	 * @param startRow
	 * @param endRow
	 */
	private void removeRow(XSSFSheet sheet, int startRow, int endRow) {
		for (int j = endRow; j >= startRow; j--) {
			if (sheet.getRow(j) == null) {
				continue;
			}
			sheet.removeRow(sheet.getRow(j));
		}
	}
}
